﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace AssetLoad
{
    public class ResourceManager : MonoBehaviour
    {
        Dictionary<string, int> loadingAsset = new Dictionary<string, int>();

        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <param name="resourcePath"></param>
		public void LoadResourceAsync(string resourcePath) {
			if (bundleContainer.ContainsKey (resourcePath)) {
				bundleContainer [resourcePath].counter ++;
			} else {
                if (loadingAsset.ContainsKey(resourcePath))
                {
                    loadingAsset[resourcePath]++;
                }
                else {
                    loadingAsset.Add(resourcePath, 1);
                    StartCoroutine(LoadResourceAsync0(resourcePath));
                }
			}
		}

        private IEnumerator LoadResourceAsync0(string resourcePath) {
            var request = Resources.LoadAsync(resourcePath);
            while (!request.isDone) {
                yield return 0;
            }
            if (loadingAsset.ContainsKey(resourcePath))
            {
                if (loadingAsset[resourcePath] <= 0)
                {
                    loadingAsset.Remove(resourcePath);
                    Debug.LogWarning("[ResourceManager] Load Resource Async Error. LoadingAsset["+resourcePath + "] <= 0.");
                    yield break;
                }
            }
            else {
                Debug.LogWarning("[ResourceManager] Load Resource Async Error. LoadingAsset Not Contains " + resourcePath);
                yield break;
            }
            bundleContainer[resourcePath] = new ObjectCounter(request.asset, loadingAsset[resourcePath]);
            loadingAsset.Remove(resourcePath);
        }


        /// <summary>
        /// 加载资源,会增加引用计数器
        /// </summary>
        /// <param name="resourcePath">资源路径</param>
        /// <returns>加载得到的资源</returns>
        public Object LoadResource(string resourcePath)
        {
            if(bundleContainer.ContainsKey(resourcePath))
            {
                bundleContainer[resourcePath].counter++;
                return bundleContainer[resourcePath].resource;
            }
            else
            {
                Object obj = Resources.Load(resourcePath);
                if(obj == null)
                {
                    Debug.LogError(resourcePath + " not exist !!!");
                }
                bundleContainer.Add(resourcePath,new ObjectCounter(obj));
                return obj;
            }
        }
        /// <summary>
        /// 卸载资源
        /// </summary>
        /// <param name="resourcePath">资源路径</param>
        public void UnloadResource(string resourcePath)
        {
            if (bundleContainer.ContainsKey(resourcePath))
            {
                if(--bundleContainer[resourcePath].counter == 0)
                {
                    bundleContainer.Remove(resourcePath);
                }
            }
            else
            {
                Debug.LogError("Unload error " + resourcePath + " has not be loaded!!!");
            }
        }
        /// <summary>
        /// 卸载资源,并立即将其从内存中清除
        /// </summary>
        /// <param name="resourcePath">资源路径</param>
        public void UnloadResourceImmediate(string resourcePath)
        {
            if (bundleContainer.ContainsKey(resourcePath))
            {
                if (--bundleContainer[resourcePath].counter == 0)
                {
                    Resources.UnloadAsset(bundleContainer[resourcePath].resource);
                    bundleContainer.Remove(resourcePath);

                }
            }
            else
            {
                Debug.LogError("Unload error " + resourcePath + " has not be loaded!!!");
            }
        }
        /// <summary>
        /// 直接获取资源，不会改动引用计数器
        /// </summary>
        /// <param name="resourcePath"></param>
        /// <returns>资源</returns>
        public Object GetResource(string resourcePath)
        {
            if(bundleContainer.ContainsKey(resourcePath))
            {
                return bundleContainer[resourcePath].resource;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 清除无用资源，卸载内存
        /// </summary>
        public void UnloadUnusedResources()
        {
            StartCoroutine(_AsycUnloadResource());
        }

        private IEnumerator _AsycUnloadResource()
        {
            yield return 1;
            yield return 1;
            Resources.UnloadUnusedAssets();
        }

        /// <summary>
        /// 资源集合
        /// </summary>
        private Dictionary<string, ObjectCounter> bundleContainer = new Dictionary<string, ObjectCounter>();

        public void Clear()
        {
            StopAllCoroutines();
            bundleContainer.Clear();
            UnloadUnusedResources();
        }
        #region 单例
        private void Awake()
        {
            instance = this;
        }

        private static ResourceManager instance;
        public static ResourceManager Instance
        {
            get
            {
                return instance;
            }
        }
        #endregion 单例
    }

    /// <summary>
    /// 资源计数器
    /// </summary>
    public class ObjectCounter
    {
        public int counter = 1;
        public Object resource;
        public ObjectCounter(Object resource, int counter = 1)
        {
            this.resource = resource;
            this.counter = counter;
        }
    }

}